package com.gszy.auth.mvc;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.rowset.serial.SerialException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * loadOnStartup 预加载当前的Servlet 项目启动时就新建一盒servlet实例 而对应的值表示加载顺序 小的先加载
 * @author MeUChT
 */

@WebServlet(name = "dispatcher",urlPatterns = "*.do",loadOnStartup = 0)
public class DispatcherServlet extends HttpServlet {
    /**
     * 项目包名
     */
    private  final String BASE_PACKAGE = "com.gszy.auth";

    /**
     * controller 包名
     */
    private final String CONTROLLER_PACKAGE = BASE_PACKAGE+".controller";

    Set<Class<?>> controllerSet = null;
    /**
     * 方法url的映射关系
     */
    Map<String, Method>  methodMap = null;

    Map<Class<?>,Object> instanceMap = new HashMap<>();

    @Override
    public void init() throws ServletException{
        controllerSet = ClassUtils.getControllerClass(CONTROLLER_PACKAGE);

        methodMap = MethodUtils.getMethodMap(CONTROLLER_PACKAGE);
    }

    @Override
    protected  void service(HttpServletRequest request, HttpServletResponse response)throws ServletException{
        //处理请求 根据url地址找到要执行的方法Method



        //获取请求的实际的地址
        String requestURI = request.getRequestURI();
        String contextPath = request.getContextPath();//获取webapp-name

        //path /test/test1.do
        String path = requestURI.replaceAll(contextPath,"");
        Method method = methodMap.get(path);


        //Method方法想要运行 需要Controller实例以及参数列表

        //先获取Controller类对象
        //1.先获取controller对应的映射路径
        String controllerPath = "/"+path.split("/")[1];
        Object controllerInstance = null;
        Object result = null;

        for (Class<?> controllerClass : controllerSet){
            Controller controllerAnno = controllerClass.getAnnotation(Controller.class);
            // /test
            String controllerRealPath = controllerAnno.value();

            if (controllerRealPath.equals(controllerPath)){
                //找到需要的Controller 类对象 然后从instanceMap 中根据Controller类对象获取实例

                Object o = instanceMap.get(controllerClass);
                if (o == null){
                    //如果之间没有实例化Controller 则进行懒加载
                    try {

                        //添加实例化对象 通过Class#newInstance === new XXX()
                        instanceMap.put(controllerClass,controllerClass.newInstance());
                        o=instanceMap.get(controllerClass);
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }

                }
                controllerInstance = o;

            }
        }
        //Method 再去获取参数列表 调用method.invoke(controllerInstance 参数列表)
        result = ParamUtils.setParameter(controllerInstance, method, request);

        //执行完成之后返回ModelAndView对象 处理结果 返回jsp页面
        setResult(result,request,response);


    }

    /**
     * 处理Controller方法返回的结果 返回的结果可能是ModelAndView也可能时String
     * @param result
     * @param request
     * @param response
     */
    private void setResult(Object result,HttpServletRequest request,HttpServletResponse response){

        if (result!=null){
            if (result instanceof String){
                try {
                    request.getRequestDispatcher((String) result).forward(request,response);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return;
            }else if (result instanceof ModelAndView){
                ModelAndView modelAndView = (ModelAndView) result;

                if(modelAndView.getPath()!=null){
                    Map<String,Object> model = modelAndView.getModel();

                    //遍历model 将键值对放在request域中
                    model.forEach((key,value)->{
                        request.setAttribute(key,value);
                    });


                    //加载数据完成后 跳转页面
                    try {
                        request.getRequestDispatcher(modelAndView.getPath()).forward(request,response);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}
